import * as THREE from 'three';
import Editor from './BaseEditor';
import { debounce } from 'lodash';

function countVisiblePointN(positions, zRange) {
  return new Promise((resolve) => {
    let pointN = 0;
    const batchSize = 200000;
    let flag = 0;
    if (positions.count === 0) resolve(pointN);
    const count = () => {
      const forMax = Math.min(flag + batchSize, positions.count);
      for (let i = flag; i < forMax; i++) {
        const z = positions.getZ(i);
        if (z <= zRange[1] && z >= zRange[0]) {
          pointN++;
        }
      }
      if (forMax < positions.count) {
        flag = forMax;
        window.requestAnimationFrame(count);
      } else {
        resolve(pointN);
      }
    };
    window.requestAnimationFrame(count);
  });
}
export default class ConfigManager {
  editor;
  constructor(editor) {
    this.editor = editor;

    this.initConfig();
  }

  initConfig() {
    let config = this.editor.state.config;
    this.editor.pc.material.setUniforms({
      // trimType: config.type === 'range-only' ? 1 : 2,
      pointSize: config.pointSize * 10,
      edgeColor: config.edgeColor,
      pointHeight: new THREE.Vector2().fromArray(config.pointHeight),
    });
  }

  countVisiblePointN = debounce(async () => {
    const config = this.editor.state.config;
    let points = this.editor.pc.groupPoints.children[0];
    let positions = points.geometry.getAttribute('position');
    config.pointInfo.vCount = await countVisiblePointN(positions, config.heightRange);
  }, 50);

  updatePointConfig(ground, intensityRange) {
    let { config } = this.editor.state;
    let points = this.editor.pc.groupPoints.children[0];
    if (!points.geometry.boundingBox) points.geometry.computeBoundingBox();
      let boundingBox = points.geometry.boundingBox;
      let position = points.geometry.getAttribute('position');
      const color = points.geometry.getAttribute('color');
      const velocity = points.geometry.getAttribute('velocity');
      let pointIntensity = config.pointIntensity;
      let pointInfo = config.pointInfo;
      pointInfo.hasIntensity = !!intensityRange;
      pointInfo.hasVelocity = velocity?.count > 0;
      pointInfo.hasRGB = color?.count > 0;
      if (intensityRange) {
        pointInfo.intensityRange.set(intensityRange[0], intensityRange[1]);
        config.pointIntensity = [
          Math.max(intensityRange[0], pointIntensity[0]),
          Math.min(intensityRange[1], pointIntensity[1]),
        ];
      } else {
          pointInfo.intensityRange.set(0, 0);
      }
      pointInfo.count = position.count;
      pointInfo.min.copy(boundingBox.min);
      pointInfo.max.copy(boundingBox.max);
      config.heightRange[0] = Math.max(config.heightRange[0], pointInfo.min.z);
      config.heightRange[1] = Math.min(config.heightRange[1], pointInfo.max.z);

      const _ground = config.pointHeight[0];
      if (_ground < pointInfo.min.z || _ground > pointInfo.max.z) {
        config.pointHeight[0] = ground;
      }
      // config.pointHeight[0] = Math.max(config.pointHeight[0], pointInfo.min.z);
      config.pointHeight[1] = Math.min(config.pointHeight[1], pointInfo.max.z);
      // config.groundValue = ground;
      this.editor.pc.ground.plane.constant = config.pointHeight[0];
      let material = points.material;
      material.setOption({
        hasIntensity: pointInfo.hasIntensity,
        hasRGB: pointInfo.hasRGB,
        hasVelocity: pointInfo.hasVelocity,
      });
      material.setUniforms({
        // groundValue: ground,
        colorRoad: -1,
        pointHeight: new THREE.Vector2().fromArray(config.pointHeight),
        pointVelocity: new THREE.Vector2().fromArray(config.pointVelocity),
        heightRange: new THREE.Vector2().fromArray(config.heightRange),
      });
  }
}